package com.hth.handle

import com.hth.model.FieldAttr
import com.hth.model.TableNameAttr
import com.intellij.openapi.project.Project
import com.intellij.psi.*
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.utils.addToStdlib.applyIf
import org.jetbrains.kotlin.utils.addToStdlib.ifFalse
import org.jetbrains.kotlin.utils.addToStdlib.ifTrue
import java.util.*
import kotlin.collections.ArrayList

/**
 * @Description:
 * @Author: hutianhua
 * @CreateTime: 2023年08月21日
 */
class PojoFiledHnadle(packageMap: MutableMap<String, String>, project: Project) {

    // 导入的包
    val packageMap = packageMap

    // 项目
    val project = project


    val map = mutableMapOf(
        "String" to "varchar(255)",
        "int" to "int",
        "Integer" to "int",
        "long" to "bigint",
        "Long" to "bigint",
        "double" to "double",
        "Double" to "double",
        "boolean" to "tinyint(1)",
        "Boolean" to "tinyint(1)",
        "char" to "char",
        "Character" to "char",
        "float" to "float",
        "Float" to "float",
        "short" to "smallint",
        "Short" to "smallint",
        "byte[]" to "BLOB",
        "byte" to "tinyint",
        "Byte" to "tinyint",
        "Date" to "datetime",
        "Timestamp" to "timestamp",
        "Time" to "TIME",
        "BigDecimal" to "decimal(18, 4)",
        "BigInteger" to "bigint",
        "LocalDateTime" to "datetime",
        "LocalDate" to "date",
    )


    fun handel(clazz: PsiClass?): List<FieldAttr> {

        val resList = arrayListOf<FieldAttr>()
        if (clazz != null && !clazz.isInterface && !clazz.isEnum) {

            val clazzAll = this.findAllClass(clazz)
            clazzAll.forEach { cl ->
                val allFields = cl.fields
                for (fields in allFields) {
                    val fieldAttr = FieldAttr()
                    // 字段名字
                    fieldAttr.name = this.camelToUnderscore(fields.name)
                    if ("serialVersionUID" == fields.name) {
                        continue
                    }
                    // java 字段类型
                    fieldAttr.javaType = fields.type.presentableText
                    fieldAttr.javaPackage = fields.type.canonicalText
                    // 解析注解
                    this.handleAnnotations(fields.annotations, fieldAttr)
                    // 解析注释
                    this.handleComment(fieldAttr, fields)
                    // 处理类型
                    fieldAttr.sqlType = fieldAttr.sqlType ?: map[fieldAttr.javaType] ?: ""
                    // 处理枚举类型
                    this.handleEnumType(fieldAttr)
                    resList.add(fieldAttr)
                }
            }
        }
        return resList;
    }

    /**
     * 处理枚举类型
     */
    private fun handleEnumType(fieldAttr: FieldAttr) {
        val enumAnno = "com.baomidou.mybatisplus.annotation.EnumValue"
        if (fieldAttr.sqlType?.isEmpty() ?: (true and fieldAttr.exist)) {
            fieldAttr.javaPackage?.apply {
                // 查找文件
                JavaPsiFacade
                    .getInstance(project)
                    .findClass(this, GlobalSearchScope.allScope(project))
                    ?.also {
                        fieldAttr.exist = false
                        // 判断是否是枚举类
                        it.isEnum.ifTrue {
                            // 获取所有枚举属性
                            var join = StringJoiner(",","(",")")
                            for (filed in it.allFields) {
                                // 枚举属性字段才加
                                if(filed.type.presentableText.equals(it.name)){
                                    join.add("'"+filed.name+"'")
                                }
                                // 属性字段上加了枚举
                                filed.getAnnotation(enumAnno)?.let {
                                    val presentableText = filed.type.presentableText
                                    fieldAttr.sqlType = map[presentableText]
                                    fieldAttr.exist = true
                                    return
                                }
                            }
                            // 字段类型是枚举
                            fieldAttr.sqlType = "enum" + join
                            fieldAttr.exist = true
                        }
                    }
            }
        }
    }

    /**
     * 解析字段的注释
     */
    private fun handleComment(fieldAttr: FieldAttr, fields: PsiField) {
        if (fieldAttr.comment.isEmpty()) {
            // 获取 Javadoc 注释
            val docComment1 = fields.docComment
                ?.descriptionElements
                ?.map { it.text?.trim()?.replace("\\", "") }
                ?.filter { it?.isNotBlank() ?: false }
                ?.joinToString(separator = ";")

            // 双斜杠注释
            val docComment2 = fields.docComment
                ?.owner
                ?.children
                ?.filter { "END_OF_LINE_COMMENT" == it.node?.elementType?.toString() }
                ?.map { it.text.trim().replace("//", "").trim() }
                ?.filter { it?.isNotBlank() ?: false }
                ?.joinToString(separator = ";")

            fieldAttr.comment = docComment1 ?: docComment2 ?: ""
        }
    }

    /**
     * 解析字段上的注解
     */
    private fun handleAnnotations(annotations: Array<PsiAnnotation>, fieldAttr: FieldAttr) {
        annotations.forEach { annotation ->
            annotation.qualifiedName?.also { it ->
                // 存在 @Id 注解直接判断为主键
                it.endsWith(".Id").ifTrue {
                    fieldAttr.majorKey = true
                    fieldAttr.notNull = true
                }

                // 兼容 mybaties-plus
                it.endsWith(".TableId").ifTrue {
                    // 存在注解 即 主键
                    fieldAttr.majorKey = true
                    fieldAttr.notNull = true
                    // 是否主键自增
                    fieldAttr.autoIncrement = annotation.findAttributeValue("type")?.text?.contains(".AUTO") ?: false
                }

                // 获取 swagger 中 @ApiModelProperty
                it.endsWith(".ApiModelProperty").ifTrue {
                    fieldAttr.comment = annotation.findAttributeValue("value")?.text?.replace("\\", "") ?: ""
                }

                // 获取 swagger 中 @Schema
                it.endsWith(".Schema").ifTrue {
                    fieldAttr.comment = annotation.findAttributeValue("description")?.text?.replace("\\", "") ?: ""
                }

                // 获取 mybaties-plus 的注解
                it.endsWith(".TableField").ifTrue {
                    // 字段名称
                    fieldAttr.name = annotation.findAttributeValue("value")?.text
                        ?.replace("\"", "")
                        ?.replace("`", "") // 处理特殊符号
                        ?.filter { !it.equals("") }
                        ?.let { camelToUnderscore(it) } // 驼峰转下划线
                        ?.let { if (it.isEmpty()) fieldAttr.name else it }

                    fieldAttr.exist = annotation.findAttributeValue("exist")?.textMatches("true") ?: false

                    // 特殊类型处理：即不能直接转换数据库类型的JAVA类型
                    fieldAttr.exist.ifTrue {
                        map.contains(fieldAttr.javaType).ifFalse {
                            fieldAttr.exist = false
                            annotation.findAttributeValue("typeHandler")?.text?.apply {
                                // 处理类型转换
                                packageMap[this]?.apply {
                                    JavaPsiFacade
                                        .getInstance(project)
                                        .findClass(this, GlobalSearchScope.allScope(project))
                                        ?.annotations
                                        ?.forEach { annotation ->
                                            // 获取类型转换
                                            annotation.qualifiedName?.endsWith(".MappedJdbcTypes")?.ifTrue {
                                                annotation.findAttributeValue("value")?.text?.let {
                                                    // varchar 类型 ,目前先兼容这个吧
                                                    it.endsWith(".VARCHAR").ifTrue {
                                                        fieldAttr.sqlType = map["String"]
                                                        fieldAttr.exist = true
                                                    }
                                                }
                                            }
                                        }
                                }
                            }
                        }
                    }
                }
            }
        }
    }


    fun findAllClass(clazz: PsiClass?): List<PsiClass> {
        // 检查传入的 clazz 是否为空
        if (clazz == null) {
            return emptyList()
        }
        // 创建一个序列，从 clazz 开始，每次迭代获取当前类的父类。
        return generateSequence(clazz) { it.superClass }
            .takeWhile { it.qualifiedName != "java.lang.Object" }
            .toList()
    }


    /**
     * 获取表注释
     */
    private fun getColumnExplain(list: Array<PsiElement>): String {
        val doc = StringJoiner(";")
        for (child in list) {
            if ("END_OF_LINE_COMMENT" == child.node?.elementType?.toString()) {
                if (child.text.trim().isNotEmpty()) {
                    doc.add(child.text.trim().replace("//", "").trim())
                }
            }
        }
        return doc.toString()
    }


    /**
     * 处理表名称
     */
    fun handleTable(clazz: PsiClass, psiFile: PsiFile): TableNameAttr {
        val tableNameAttr = TableNameAttr()

        // 先获取注解上表明
        val tableName = clazz.getAnnotation("com.baomidou.mybatisplus.annotation.TableName")
        if (tableName != null) {
            val findAttributeValue = tableName.findAttributeValue("value")
            if (findAttributeValue != null) {
                tableNameAttr.name = findAttributeValue.text.trim().replace("\"", "").trim()
            }
        }
        // 没有注解 或者注解没有设置 使用表明
        if (tableNameAttr.name == null) {
            val name = clazz.name!!
            tableNameAttr.name = this.camelToUnderscore(name)
        }
        // 获取表的注释
        val apiModel = clazz.getAnnotation("io.swagger.annotations.ApiModel")
        if (apiModel != null) {
            val findAttributeValue = apiModel.findAttributeValue("value")
            if (findAttributeValue != null) {
                tableNameAttr.comment = findAttributeValue.text.trim().replace("\"", "").trim()
            }
        }
        // 没有使用swagger 获取注释
        if (tableNameAttr.comment == null) {
            val docComment = clazz.docComment
            if (docComment != null) {
                // 获取javadoc 注释文档上的注释
                val docList = ArrayList<String>()
                for (dowels in docComment.descriptionElements) {
                    if (dowels.text?.trim() != null && dowels.text.trim().isNotEmpty()) {
                        docList.add(dowels.text.replace("\"", ""))
                    }
                }
                tableNameAttr.comment = docList.joinToString(";")
                // 获取双斜杠的注释
                if (tableNameAttr.comment == null) {
                    val owner = docComment.owner
                    if (owner != null) {
                        tableNameAttr.comment = this.getColumnExplain(owner.children)
                    }
                }
            } else {
                // 获取双斜线注释
                tableNameAttr.comment = this.getColumnExplain(psiFile.children)

            }
        }


        return tableNameAttr
    }


    /**
     * 驼峰转下滑线
     */
    fun camelToUnderscore(param: String): String {
        val str = param.trim()
        if (str.isEmpty()) return ""
        val list = mutableListOf<String>()
        var i = 1
        var j = 0
        while (i < str.length) {
            if (str[i] in 'A'..'Z') {
                list.add(str.substring(j, i))
                j = i
            }
            i++
        }
        list.add(str.substring(j))
        return list.joinToString("_") { it.lowercase(Locale.getDefault()) }
    }


}
